package com.googlecode.klenwell.playndev.core;

import static playn.core.PlayN.graphics;
import static playn.core.PlayN.pointer;

import java.util.Date;

import org.jbox2d.common.Vec2;

import playn.core.Canvas;
import playn.core.CanvasImage;
import playn.core.Color;
import playn.core.Game;
import playn.core.GroupLayer;
import playn.core.ImageLayer;
import playn.core.ImmediateLayer;
import playn.core.Pointer;
import playn.core.Surface;

import com.googlecode.klenwell.playndev.core.event.EventApi;
import com.googlecode.klenwell.playndev.core.event.EventType;
import com.googlecode.klenwell.playndev.core.event.GameEvent;

public class PlaynDev implements Game {
    
    public static Integer frameNum = 0;
    public static Long startTime = System.currentTimeMillis();

	CanvasImage bgImage;
	ImageLayer bgLayer;
	private GroupLayer rootLayer = graphics().rootLayer();
	Circle redCircle = new Circle(-25, 0, 50, Color.rgb(255, 0, 0), 0.5f);
	Circle whiteCircle = new Circle(0, 0, 50, Color.rgb(255, 255, 255), 0.5f);
	Circle blueCircle = new Circle(25, 0, 50, Color.rgb(0, 0, 255), 0.5f);

	/*
	 * Core PlayN Methods
	 */
	@Override
	public void init() {
		bgImage = graphics().createImage(graphics().width(),
				graphics().height());
		Canvas canvas = bgImage.canvas();
		canvas.setFillColor(Color.rgb(0, 0, 0));
		canvas.fillRect(0, 0, graphics().width(), graphics().height());
		bgLayer = graphics().createImageLayer(bgImage);
		bgLayer.setAlpha(0.50f);
		
		initEventHandling();
		
		// test http://stackoverflow.com/a/10161338/1093087
		GraphicsApi.log("Min,Max Int: " + Integer.MIN_VALUE + " / " + Integer.MAX_VALUE);
	}

	private void initEventHandling() {
	    /*
	     * For event-handling example, see Playn-Sample code:
	     * http://goo.gl/Oy6RJ
	     * 
	     * This creates a central handler for events
	     */
	    pointer().setListener(new Pointer.Listener() {
	        @Override
            public void onPointerStart(Pointer.Event event) {
	            GameEvent gameEvent = EventApi.normalizeEvent(EventType.POINTERSTART, event);
	            EventApi.enqueue(gameEvent);
            }
	        
            @Override
            public void onPointerEnd(Pointer.Event event) {
                GameEvent gameEvent = EventApi.normalizeEvent(EventType.POINTEREND, event);
                EventApi.enqueue(gameEvent);
            }

            @Override
            public void onPointerDrag(Pointer.Event event) {
                GameEvent gameEvent = EventApi.normalizeEvent(EventType.POINTERDRAG, event);
                EventApi.enqueue(gameEvent);
            }
        });
	    
	    // bind listeners to targets (circles)
	    EventApi.bind(EventType.POINTERSTART, redCircle, "hitCheck");
	    EventApi.bind(EventType.POINTEREND, redCircle, "pointerEnd");
	    EventApi.bind(EventType.POINTERDRAG, redCircle, "beingDragged");
	    EventApi.bind(EventType.POINTERSTART, blueCircle, "hitCheck");
	    EventApi.bind(EventType.POINTEREND, blueCircle, "pointerEnd");
        EventApi.bind(EventType.POINTERDRAG, blueCircle, "beingDragged");
    }

    @Override
	public void paint(float alpha) {
		trimRootLayer();
		drawTransparentImageLayers();
		GraphicsApi.displayLog();
	}

	@Override
	public void update(float delta) {
	    EventApi.processQueue();
		randomlyMoveCircles();
		
		frameNum++;
		if ( frameNum % 25 == 0 ) {
		    Integer secElapsed = (int) (System.currentTimeMillis() - startTime) / 1000;
		    float fps = frameNum.floatValue() / secElapsed.floatValue();
		    GraphicsApi.log("FPS: " + fps);
		}
	}

	@Override
	public int updateRate() {
		return 25;
	}

	/*
	 * Additional Methods
	 */
	public void randomlyMoveCircles() {
		redCircle.pt.addLocal(new Vec2(randomInt(-1, 1), randomInt(-1, 1)));
		whiteCircle.pt.addLocal(new Vec2(randomInt(-1, 1), randomInt(-1, 1)));
		blueCircle.pt.addLocal(new Vec2(randomInt(-1, 1), randomInt(-1, 1)));
	}

	private Integer randomInt(int min, int max) {
		return min + (int) (Math.random() * ((max - min) + 1));
	}

	public void drawTransparentImageLayers() {
	    // THIS WORKS
		GroupLayer groupLayer = graphics().createGroupLayer();
		groupLayer.add(bgLayer);
		groupLayer.add(redCircle.asImageLayer());
		groupLayer.add(whiteCircle.asImageLayer());
		groupLayer.add(blueCircle.asImageLayer());
		rootLayer.add(groupLayer);
	}

	public void drawTransparentCanvasImages() {
	    // DOES NOT WORK FOR TRANSPARENCY
		// create an immediate layer and add to root layer
		ImmediateLayer circleLayer = graphics().createImmediateLayer(
				new ImmediateLayer.Renderer() {
					public void render(Surface surf) {
						Circle redCircle = new Circle(-25, 0, 50, Color.rgb(
								255, 0, 0), 0.5f);
						Circle whiteCircle = new Circle(0, 0, 50, Color.rgb(
								255, 255, 255), 0.5f);
						Circle blueCircle = new Circle(25, 0, 50, Color.rgb(0,
								0, 255), 0.5f);
						surf.drawImage(redCircle.asCanvasImage(),
								redCircle.getScreenX(), redCircle.getScreenY());
						surf.drawImage(whiteCircle.asCanvasImage(),
								whiteCircle.getScreenX(),
								whiteCircle.getScreenY());
						surf.drawImage(blueCircle.asCanvasImage(),
								blueCircle.getScreenX(),
								blueCircle.getScreenY());
					}
				});

		// rootLayer.setAlpha(0.5f);
		rootLayer.add(circleLayer);
	}

	private void trimRootLayer() {
		int rootLayerMaxSize = 20;
		while (rootLayer.size() > rootLayerMaxSize) {
			rootLayer.remove(rootLayer.get(0));
		}
	}
}
